home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-04-03 | 14.4 KB | 1,056 lines |
- .include "lib/global.h"
-
- .refresh_OAM = 0xFF80
-
- ; Main user routine
- .globl _main
-
- ; ****************************************
- ; Beginning of module
- .title "GB Runtime"
- .module Runtime
- .area HEADER (ABS)
-
- ; Standard header for the GB
- .org 0x00
-
- ; IRQ vectors
- .org 0x40
- JP 0x60
-
- .org 0x48
- RETI
-
- .org 0x50
- RETI
-
- .org 0x58
- RETI
-
- .org 0x60
- PUSH AF
- ; PUSH BC
- ; PUSH DE
- ; PUSH HL
- CALL .refresh_OAM
- ; POP HL
- ; POP DE
- ; POP BC
- POP AF
- RETI
-
- ; GameBoy Header
-
- .org 0x100
- ; Standard Nintendo DO NOT CHANGE...
- NOP
- JP 0x150
- .byte 0xCE,0xED,0x66,0x66
- .byte 0xCC,0x0D,0x00,0x0B
- .byte 0x03,0x73,0x00,0x83
- .byte 0x00,0x0C,0x00,0x0D
- .byte 0x00,0x08,0x11,0x1F
- .byte 0x88,0x89,0x00,0x0E
- .byte 0xDC,0xCC,0x6E,0xE6
- .byte 0xDD,0xDD,0xD9,0x99
- .byte 0xBB,0xBB,0x67,0x63
- .byte 0x6E,0x0E,0xEC,0xCC
- .byte 0xDD,0xDC,0x99,0x9F
- .byte 0xBB,0xB9,0x33,0x3E
-
- .org 0x134
- ; Title of the game
- .asciz "Title"
-
- .org 0x144
- ; Not used
-
- .org 0x147
- ; Cartridge type is ROM only
- .byte 0
-
- .org 0x148
- ; ROM size is 32kB
- .byte 0
-
- .org 0x149
- ; RAM size is 0kB
- .byte 0
-
- .org 0x14A
- ; Maker ID
- .byte 0x00,0x00
-
- .org 0x14C
- ; Version number
- .byte 0x01
-
- .org 0x14D
- ; Complement check
- .byte 0x00
-
- .org 0x14E
- ; Checksum
- .byte 0x00,0x00
-
- ; ****************************************
- .org 0x150
- ; Beginning of the code
- DI ; Disable interrupts
- LD SP,#0xCFFF ; Initialize the stack
- XOR A ; A = 0
- LD (.mode),A
- LD HL,#0xDFFF ; Clear from 0xD000 to 0xDFFF
- LD C,#0x10
- LD B,#0x00
- 1$:
- LD (HL-),A
- DEC B
- JR NZ,1$
- DEC C
- JR NZ,1$
- CALL .clear_OAM
- ; Copy refresh_OAM routine to HIRAM
- LD C,#.refresh_OAM-0xFF00
- LD HL,#.start_refresh_OAM
- LD B,#.end_refresh_OAM-.start_refresh_OAM
- 2$:
- LD A,(HL+)
- LDH (C),A
- INC C
- DEC B
- JR NZ,2$
- XOR A ; A = 0
- LDH (.SCROLLY),A
- LDH (.SCROLLX),A
- LD A,#0b10000000 ; LCD = On
- ; WindowBank = 0x9800
- ; Window = Off
- ; BG Chr = 0x8800
- ; BG Bank = 0x9800
- ; OBJ = 8x8
- ; OBJ = Off
- ; BG = Off
- LDH (.LCDCONT),A
- CALL .wait_vbl ; Must be in VBL before turning the screen off.
- LD A,#0b00000011
- ; LCD = Off
- ; WindowBank = 0x9800
- ; Window = Off
- ; BG Chr = 0x8800
- ; BG Bank = 0x9800
- ; OBJ = 8x8
- ; OBJ = On
- ; BG = On
- LDH (.LCDCONT),A
- CALL .std_pal
- LD A,#0x01
- LD (0x2000),A ; ROM bank 1
- LD A,#0x40
- LDH (.LCDSTAT),A
- LD A,#0b00000011
- ; Pin P10-P13 = Off
- ; Serial I/O = Off
- ; Timer Ovfl = Off
- ; LCDC = On
- ; V-Blank = On
- LDH (.ISWITCH),A
- XOR A ; A = 0
- LDH (.IFLAGS),A
-
- ; Call the main function
- CALL _main
-
- 3$:
- JR 3$ ; Wait forever
-
- .org .MODE_TABLE
- ; Jump table for modes
- RET
-
- ; ****************************************
-
- ; Ordering of segments for the linker
- .area _CODE
- .area _DATA
- .area _LIT
-
- .area _BSS
-
- ; We should be at address 0xC000
- .OAM: ; DMA transfer must start at multiples of 0x100
- .ds 0xA0
-
- .mode:
- .ds 0x01
-
- ; Runtime library
- .area _CODE
-
- ; Shift HL left arithmetically by DE
- .asl::
- .lsl::
- LD A,D
- OR E
- RET Z
- PUSH DE
- 1$:
- ADD HL,HL
- DEC DE
- LD A,D
- OR E
- JR NZ,1$
- POP DE
- RET
-
- ; Shift HL right arithmetically by DE
- .asr::
- LD A,D
- OR E
- RET Z
- PUSH DE
- 1$:
- SRA H ; Shift right
- RR L
- DEC DE
- LD A,D
- OR E
- JR NZ,1$
- POP DE
- RET
-
- ; Shift HL right logically by DE
- .lsr::
- LD A,D
- OR E
- RET Z
- PUSH DE
- 1$:
- SRL H ; Shift right
- RR L
- DEC DE
- LD A,D
- OR E
- JR NZ,1$
- POP DE
- RET
-
- ; HL = DE * HL [signed]
- .mul::
- .mulu::
- PUSH BC
- LD B,H
- LD C,L
- LD HL,#0x00
- 1$:
- LD A,C
- RRCA
- JR NC,2$
- ADD HL,DE
- 2$:
- SRL B
- RR C
- LD A,C
- OR B
- JR Z,3$
- SLA E
- RL D
- LD A,D
- OR E
- JR NZ,1$
- 3$:
- POP BC
- RET
-
- ; 16-bit x 16-bit Division Subroutine
- ;
- ; This subroutine divides the 16-bit quantity in register
- ; pair DE by the 16-bit quantity in register pair BC.
- ; The result will be stored in register pair DE and the
- ; remainder in register pair BC.
-
- ; * Ram memory variables *
-
- .area _BSS
-
- .divsgn:
- .ds 0x01
-
- .divtmp:
- .ds 0x02
-
- .divcnt:
- .ds 0x01
-
- .area _CODE
-
- .div::
- .mod::
- PUSH HL
- LD HL,#.divsgn ; Load HL with symbolic address
- LD (HL),#0x01
- BIT 7,B ; Is BC negative?
- CALL NZ,5$ ; Yes -> Negate it
- BIT 7,D ; Is DE negative?
- CALL NZ,7$ ; Yes -> Negate it
- LD HL,#.divtmp ; Load HL with symbolic address
- LD (HL),C ; Save the LS byte of the divisor
- INC HL
- LD (HL),B ; Save the MS byte of the divisor
- INC HL
- LD (HL),#0x11 ; Save the divisor's bit count (decimal 17)
- LD BC,#0x00 ; BC will store the partial dividend
- 1$:
- LD HL,#.divcnt ; Load HL with address of bit count (dec 17)
- RL E ; Rotate the LSB into carry
- RL D ; Rotate the MSB into carry
- DEC (HL) ; Decrement the bit count
- JR Z,3$ ; Return if zero
- RL C ; Rotate the MSB of the dividend into
- RL B ; the partial dividend stored in BC
- DEC HL ; Point HL to divisor in memory
- DEC HL
- LD A,C ; Get the LS byte of partial dividend
- SUB (HL) ; Subtract the LS byte of the divisor
- LD C,A
- INC HL
- LD A,B ; Get the MS byte of partial dividend
- SBC (HL) ; Subtract with borrow the divisor
- LD B,A
- JR NC,2$ ; If carry=0, do not add divisor to
- ; the result of previous subtraction
- DEC HL
- LD A,C ; The divisor is larger than the partial
- ADD (HL) ; dividend, so the divisor must be
- LD C,A ; added to the result of the subtraction
- INC HL ; so that the previous value of the
- LD A,B ; partial dividend is re-established.
- ADC (HL)
- LD B,A
- 2$:
- CCF ; Complement the carry
- JR 1$
- 3$:
- LD HL,#.divsgn ; Load HL with symbolic address
- XOR A ; A = 0
- CP (HL) ; Was divisor xor dividend negative?
- JR NZ,4$ ; No
- CALL 6$ ; Yes -> Negate results
- CALL 8$
- 4$:
- POP HL
- RET
-
- 5$:
- DEC (HL)
- 6$:
- LD A,B
- CPL
- LD B,A
- LD A,C
- CPL
- LD C,A
- INC BC
- RET
- 7$:
- DEC (HL)
- 8$:
- LD A,D
- CPL
- LD D,A
- LD A,E
- CPL
- LD E,A
- INC DE
- RET
-
- .divu::
- .modu::
- PUSH HL
- LD HL,#.divtmp ; Load HL with symbolic address
- LD (HL),C ; Save the LS byte of the divisor
- INC HL
- LD (HL),B ; Save the MS byte of the divisor
- INC HL
- LD (HL),#0x11 ; Save the divisor's bit count (decimal 17)
- LD BC,#0x00 ; BC will store the partial dividend
- 1$:
- LD HL,#.divcnt ; Load HL with address of bit count (dec 17)
- RL E ; Rotate the LSB into carry
- RL D ; Rotate the MSB into carry
- DEC (HL) ; Decrement the bit count
- JR Z,3$ ; Return if zero
- RL C ; Rotate the MSB of the dividend into
- RL B ; the partial dividend stored in BC
- DEC HL ; Point HL to divisor in memory
- DEC HL
- LD A,C ; Get the LS byte of partial dividend
- SUB (HL) ; Subtract the LS byte of the divisor
- LD C,A
- INC HL
- LD A,B ; Get the MS byte of partial dividend
- SBC (HL) ; Subtract with borrow the divisor
- LD B,A
- JR NC,2$ ; If carry=0, do not add divisor to
- ; the result of previous subtraction
- DEC HL
- LD A,C ; The divisor is larger than the partial
- ADD (HL) ; dividend, so the divisor must be
- LD C,A ; added to the result of the subtraction
- INC HL ; so that the previous value of the
- LD A,B ; partial dividend is re-established.
- ADC (HL)
- LD B,A
- 2$:
- CCF ; Complement the carry
- JR 1$
- 3$:
- POP HL
- RET
-
- ; Call the initialization function for the mode specified in HL
- .set_mode:
- LD A,L
- LD (.mode),A
-
- LD BC,#.MODE_TABLE
- SLA L ; Multiply mode by 4
- SLA L
- ADD HL,BC
- JP (HL) ; Jump to initialization routine
-
- ; Wait until all buttons have been released and debounced
- .padup:
- PUSH AF ; Save modified registers
- PUSH BC
- 1$:
- LD B,#0xFF
- 2$:
- CALL .jpad
- OR A ; Have all buttons been released ?
- JR NZ,1$ ; Not yet
-
- DEC B
- JR NZ,2$
- POP BC ; Restore registers
- POP AF
- RET
-
- ; Get Keypad Button Status
- ; The following bits are set if pressed:
- ; 0x80 - Start 0x08 - Down
- ; 0x40 - Select 0x04 - Up
- ; 0x20 - B 0x02 - Left
- ; 0x10 - A 0x01 - Right
- .jpad:
- PUSH BC ; Save modified registers
- LD A,#0x20
- LDH (.JOYPAD),A ; Turn on P15
-
- LDH A,(.JOYPAD) ; Delay
- LDH A,(.JOYPAD)
- CPL
- AND #0x0F
- SWAP A
- LD B,A
- LD A,#0x10
- LDH (.JOYPAD),A ; Turn on P14
- LDH A,(.JOYPAD) ; Delay
- LDH A,(.JOYPAD)
- LDH A,(.JOYPAD)
- LDH A,(.JOYPAD)
- LDH A,(.JOYPAD)
- LDH A,(.JOYPAD)
- CPL
- AND #0x0F
- OR B
- SWAP A
- POP BC ; Restore registers
- RET
-
- ; Wait for the key in B to be pressed
- .wait_pad:
- 1$:
- CALL .jpad ; Hold startup screen until start is pressed
- AND B ; Compare with mask ?
- JR Z,1$ ; No
- RET
-
- ; Wait for VBL
- .wait_vbl:
- LDH A,(.LCDCONT)
- ADD A,A
- RET NC
-
- 1$:
- LDH A,(.CURLINE) ; 0xFF44 = LCD Y-Pos
- CP #0x90 ; 0x90 and bigger = in VBL
- JR NZ,1$ ; Loop until it $90
- RET
-
- ; Wait for BC ns
- .delay_ns:
- 1$:
- DEC BC
- LD A,B
- OR C
- JR NZ,1$
-
- RET
-
- ; Wait for BC ms
- .delay_ms:
- PUSH DE
- LD DE,#00
- 1$:
- DEC DE
- LD A,D
- OR E
- JR NZ,1$
- DEC BC
- LD A,B
- OR C
- JR NZ,1$
- POP DE
-
- RET
-
- ; All colors to transparent
- .white:
- XOR A ; A = 0
- LDH (.BGRDPAL),A
- RET
-
- ; All colors to black
- .black:
- LD A,#0xFF
- LDH (.BGRDPAL),A
- RET
-
- ; Sets the colors to normal palette
- .std_pal:
- LD A,#0b11100100 ; Grey 3 = 11 (Black)
- ; Grey 2 = 10 (Dark grey)
- ; Grey 1 = 01 (Light grey)
- ; Grey 0 = 00 (Transparent)
- LDH (.BGRDPAL),A
- LDH (.SPR0PAL),A
- LD A,#0b00011011
- LDH (.SPR1PAL),A
- RET
-
- ; Initialize the tile set at HL with A
- .init_tiles:
- LD C,#0x10
- LD B,#0x00
- 1$:
- LD (HL+),A
- DEC B
- JR NZ,1$
- DEC C
- JR NZ,1$
- RET
-
- ; Initialize part of the tile set from (BC) to (HL)
- ; of size DE bytes
- .mv_tiles:
- 1$:
- LDH A,(.LCDSTAT)
- AND #0x02
- JR NZ,1$
-
- LD A,(BC)
- LD (HL+),A
- INC BC
- DEC DE
- LD A,D
- OR E
- JR NZ,1$
- RET
-
- ; Set background tile table to table starting at (BC)
- .set_btt:
- LD HL,#0x9800
- JR .set_tt
-
- ; Set window tile table to table starting at (BC)
- .set_wtt:
- LD HL,#0x9C00
-
- .set_tt:
- LD DE,#0x0400 ; One whole GB Screen
-
- 1$:
- LDH A,(.LCDSTAT)
- AND #0x02
- JR NZ,1$
-
- LD A,(BC)
- LD (HL+),A
- INC BC
- DEC DE
- LD A,D
- OR E
- JR NZ,1$
-
- RET
-
- ; Set background tile table to B
- .init_btt:
- LD HL,#0x9800
- JR .init_tt
-
- ; Set window tile table to B
- .init_wtt:
- LD HL,#0x9C00
-
- .init_tt:
- LD DE,#0x0400 ; One whole GB Screen
-
- 1$:
- LDH A,(.LCDSTAT)
- AND #0x02
- JR NZ,1$
-
- LD A,B
- LD (HL+),A
-
- DEC DE
- LD A,D
- OR E
- JR NZ,1$
-
- RET
-
- ; Set background tile table from BC at xy = DE of size wh = HL
- ; wh >= (1,1)
- .set_xy_btt:
- PUSH HL
- LD HL,#0x9800 ; Calculate origin
- JR .set_xy_tt
-
- ; Set window tile table from BC at xy = DE of size wh = HL
- ; wh >= (1,1)
- .set_xy_wtt:
- PUSH HL
- LD HL,#0x9C00 ; Calculate origin
-
- .set_xy_tt:
- PUSH BC
- XOR A ; A = 0
- OR E
- JR Z,2$
-
- LD BC,#0x20
- 1$:
- ADD HL,BC ; y coordinate
- DEC E
- JR NZ,1$
- 2$:
- LD B,#0x00 ; x coordinate
- LD C,D
- ADD HL,BC
-
- POP BC
- POP DE ; DE = wh
- PUSH HL ; Store origin
- PUSH DE ; Store wh
- 3$:
- LDH A,(.LCDSTAT)
- AND #0x02
- JR NZ,3$
-
- LD A,(BC)
- LD (HL+),A
- INC BC
- DEC D
- JR NZ,3$
- POP HL ; Get wh
- LD D,H ; Restore D = w
- POP HL ; Get origin
- DEC E
- JR Z,4$
-
- PUSH BC ; Next line
- LD BC,#0x20
- ADD HL,BC
- POP BC
-
- PUSH HL ; Store current line
- PUSH DE ; Store wh
- JR 3$
- 4$:
- RET
-
- ; Move sprite number C at xy = DE
- .mv_sprite:
- LD HL,#.OAM ; Calculate origin of sprite info
-
- SLA C ; Multiply C by 4
- SLA C
- LD B,#0x00
- ADD HL,BC
-
- LD A,E
- LD (HL+),A
-
- LD A,D
- LD (HL+),A
- RET
-
- ; Set sprite number C to tile D
- .set_sprite:
- LD HL,#.OAM ; Calculate origin of sprite info
-
- SLA C ; Multiply C by 4
- SLA C
- LD B,#0x00
- ADD HL,BC
- INC HL ; Add 2
- INC HL
-
- LD A,D
- LD (HL),A
- RET
-
- ; Set properties of sprite number C to D
- .prop_sprite:
- LD HL,#.OAM ; Calculate origin of sprite info
-
- SLA C ; Multiply C by 4
- SLA C
- LD B,#0x00
- ADD HL,BC
- INC HL ; Add 3
- INC HL
- INC HL
-
- LD A,D
- LD (HL),A
- RET
-
- ; Clear OAM data
- .clear_OAM:
- LD B,#0xA0 ; Clear OAM
- LD HL,#.OAM
- XOR A ; A = 0
- 1$:
- LD (HL+),A
- DEC B
- JR NZ,1$
- RET
-
- ; Copy OAM data to OAM RAM
- .start_refresh_OAM:
- LD A,#0xC0 ; OAM data address (0xC000)
- LDH (.DMA),A ; Put A into DMA registers
- LD A,#0x28 ; We need to wait 160 ns
- 1$:
- DEC A
- JR NZ,1$
- RET
- .end_refresh_OAM:
-
- _mode::
- LDA HL,2(SP)
- LD L,(HL)
- LD H,#0x00
- CALL .set_mode
- RET
-
- _delay::
- PUSH BC
- LDA HL,4(SP)
- LD C,(HL)
- INC HL
- LD B,(HL)
- CALL .delay_ns
- POP BC
- RET
-
- _pause::
- PUSH BC
- LDA HL,4(SP)
- LD C,(HL)
- INC HL
- LD B,(HL)
- CALL .delay_ms
- POP BC
- RET
-
- _joypad::
- CALL .jpad
- LD H,#0x00 ; Return result in HL
- LD L,A
- RET
-
- _waitpad::
- PUSH BC
- LDA HL,4(SP)
- LD B,(HL)
- CALL .wait_pad
- LD H,#0x00 ; Return result in HL
- LD L,A
- POP BC
- RET
-
- _waitpadup::
- CALL .padup
- RET
-
- _enable_interrupts::
- EI
- RET
-
- _disable_interrupts::
- DI
- RET
-
- _display_on::
- LDH A,(.LCDCONT)
- OR #0x80
- LDH (.LCDCONT),A
- RET
-
- _display_off::
- CALL .wait_vbl ; Must be in VBL before turning the screen off.
- LDH A,(.LCDCONT)
- AND #0xFF-0x80
- LDH (.LCDCONT),A
- RET
-
- _show_bkg::
- LDH A,(.LCDCONT)
- OR #0x01
- LDH (.LCDCONT),A
- RET
-
- _hide_bkg::
- LDH A,(.LCDCONT)
- AND #0xFF-0x01
- LDH (.LCDCONT),A
- RET
-
- _set_bkg_data::
- PUSH BC
- PUSH DE
-
- LDA HL,11(SP)
- LD B,(HL) ; data
- DEC HL
- LD C,(HL)
- DEC HL
- LD D,(HL) ; nb_tiles
- DEC HL
- LD E,(HL)
- DEC HL
- LD A,(HL-) ; first_tile
- LD L,(HL)
- LD H,A
-
- PUSH HL
- LD H,D
- LD L,E
- ADD HL,HL ; HL *= 16
- ADD HL,HL
- ADD HL,HL
- ADD HL,HL
- LD D,H
- LD E,L
- POP HL
-
- ADD HL,HL ; HL *= 16
- ADD HL,HL
- ADD HL,HL
- ADD HL,HL
-
- PUSH BC
- LD BC,#0x9000
- ADD HL,BC
- POP BC
-
- CALL .mv_tiles
-
- POP DE
- POP BC
- RET
-
- _set_bkg_tiles::
- PUSH BC
- PUSH DE
-
- LDA HL,6(SP)
- LD D,(HL) ; x
- INC HL
- INC HL
- LD E,(HL) ; y
- LDA HL,15(SP)
- LD B,(HL) ; tilelist
- DEC HL
- LD C,(HL)
- DEC HL
- DEC HL
- LD A,(HL-) ; h
- DEC HL
- LD H,(HL) ; w
- LD L,A
-
- CALL .set_xy_btt
-
- POP DE
- POP BC
- RET
-
- _scroll_bkg::
- LDA HL,2(SP)
- XOR A ; A = 0
- CP (HL)
- JR Z,1$
-
- LDH A,(.SCROLLX)
- ADD (HL)
- LDH (.SCROLLX),A
- 1$:
- INC HL
- INC HL
- XOR A ; A = 0
- CP (HL)
- JR Z,2$
-
- LDH A,(.SCROLLY)
- ADD (HL)
- LDH (.SCROLLY),A
- 2$:
- RET
-
- _show_window::
- LDH A,(.LCDCONT)
- OR #0x20
- LDH (.LCDCONT),A
- RET
-
- _hide_window::
- LDH A,(.LCDCONT)
- AND #0xFF-0x20
- LDH (.LCDCONT),A
- RET
-
- _show_sprites::
- LDH A,(.LCDCONT)
- OR #0x02
- LDH (.LCDCONT),A
- RET
-
- _hide_sprites::
- LDH A,(.LCDCONT)
- AND #0xFF-0x02
- LDH (.LCDCONT),A
- RET
-
- _sprites8x8::
- LDH A,(.LCDCONT)
- AND #0xFF-0x04
- LDH (.LCDCONT),A
- RET
-
- _sprites8x16::
- LDH A,(.LCDCONT)
- OR #0x04
- LDH (.LCDCONT),A
- RET
-
- _set_sprite_data::
- PUSH BC
- PUSH DE
-
- LDA HL,11(SP)
- LD B,(HL) ; data
- DEC HL
- LD C,(HL)
- DEC HL
- LD D,(HL) ; nb_tiles
- DEC HL
- LD E,(HL)
- DEC HL
- LD A,(HL-) ; first_tile
- LD L,(HL)
- LD H,A
-
- PUSH HL
- LD H,D
- LD L,E
- ADD HL,HL ; HL *= 16
- ADD HL,HL
- ADD HL,HL
- ADD HL,HL
- LD D,H
- LD E,L
- POP HL
-
- ADD HL,HL ; HL *= 16
- ADD HL,HL
- ADD HL,HL
- ADD HL,HL
-
- PUSH BC
- LD BC,#0x8000
- ADD HL,BC
- POP BC
-
- CALL .mv_tiles
-
- POP DE
- POP BC
- RET
-
- _set_sprite_tile::
- PUSH BC
- PUSH DE
-
- LDA HL,6(SP)
- LD C,(HL) ; nb
- INC HL
- INC HL
- LD D,(HL) ; tile
-
- CALL .set_sprite
-
- POP DE
- POP BC
- RET
-
- _set_sprite_prop::
- PUSH BC
- PUSH DE
-
- LDA HL,6(SP)
- LD C,(HL) ; nb
- INC HL
- INC HL
- LD D,(HL) ; prop
-
- CALL .prop_sprite
-
- POP DE
- POP BC
- RET
-
- _move_sprite::
- PUSH BC
- PUSH DE
-
- LDA HL,6(SP)
- LD C,(HL) ; nb
- INC HL
- INC HL
- LD D,(HL) ; x
- INC HL
- INC HL
- LD E,(HL) ; y
-
- CALL .mv_sprite
-
- POP DE
- POP BC
- RET
-